#include <task.h>
#include "task_list.h"
#include "task_desc.h"

/********************************
 * Semaphore waiters management *
 ********************************/

void task_sem_add_waiter (task_sem_t *sem, task_t task) {
  if (!sem->waiters_head)
    sem->waiters_head = sem->waiters_tail = task;
  else
    sem->waiters_tail->next_waiter = task;
  task->next_waiter = NULL;
}

task_t task_sem_pop_waiter (task_sem_t *sem) {
  task_t task;
  if (sem->waiters_head) {
    task = sem->waiters_head;
    sem->waiters_head = sem->waiters_head->next_waiter;
  } else
    task = NULL;
  return task;
}

/*****************
 * Semaphore API *
 *****************/

int task_sem_init (task_sem_t *sem, int val) {
  sem->val = val;
  sem->waiters_head = NULL;
  sem->waiters_tail = NULL;
  return 1;
}

int task_sem_post (task_sem_t *sem) {
  if (sem->val++ < 0) {
    task_t waiter = task_sem_pop_waiter (sem);
    if (waiter)
      waiter->state = TS_RUNNING;
  }
  return 1;
}

int task_sem_wait (task_sem_t *sem) {
  if (--sem->val < 0) {
    task_sem_add_waiter (sem, current_task);
    current_task->state = TS_SLEEPING;
    task_cooperate ();
  }
  return 1;
}
